/**
 * Clase que representa elasticos reales como objetos elasticos.
 * extiende de <b>PhysicsElement</b>
 */
public class Rubber extends PhysicsElement {
   private static int id=0;  // Spring identification
   protected final float restLength;
   private float stiffness;
   protected AttachableElement a_end, b_end;
 /**
 *constructor por defecto.
 */

   private Rubber(){
       super(id++);
       stiffness = restLength = 0;
    }

   /**
    * constructor que incluye el largo en reposo y la constante elastica.
    * @param restLength largo original.
    * @param stiffness constante elastica.
    */
   public Rubber(float restLength, float stiffness)
      {
      super(id++);
      this.restLength = restLength;
      this.stiffness = stiffness;
      a_end = b_end = null;
   }
   /**
    * setea un nuevo valor de constante elastica (stiffness)
    * @param a nuevo valor de stiffness
    */
   public void set_stiffness(float a){
       stiffness=a;
   }
   /**
    * obtiene valor de constante elastica
    * @return stiffness constante elastica actual
    */
   public float get_stiffness(){
   return stiffness;
   }
   /**
    * adjunta objeto ae en la punta A del elastico.
    * @param ae objeto de clase <b>AttachableElement</b> en extremo A
    */
   public void attachAend (AttachableElement ae) {
      a_end = ae;
      ae.attachRubber(this);
   }
   /**
    * separa al objeto enlazado a la punta A del elastico.
    */
   public void detachAend(){
      if (a_end == null) return;
      a_end.detachRubber(this);
      a_end=null;
   }
   /**
    * adjunta objeto ae en la punta B del elastico.
    * @param ae objeto de clase <b>AttachableElement</b> en extremo B
    */
   public void attachBend (AttachableElement ae) {
      b_end = ae;
      ae.attachRubber(this);
   }
   /**
    * separa al objeto enlazado a la punta B del elastico.
    */
   public void detachBend(){
      if (b_end == null) return;
      b_end.detachRubber(this);
      b_end = null;
   }
/**
 * obtiene la posicion del extremo A del elastico.
 * @return Vector2D() posicion extremo A
 */
   public Vector2D getAendPosition() {
      if (a_end != null)
         return a_end.getPosition();
      if (b_end != null)
         return b_end.getPosition().minus(new Vector2D(0,restLength));
      return new Vector2D();
   }
   /**
    * obtiene la posicion del extremo B del elastico.
    * @return Vector2D() posición extremo B
    */
   public Vector2D getBendPosition() {
      if (b_end != null)
         return b_end.getPosition();
      if (a_end != null)
         return a_end.getPosition().plus(new Vector2D(0,restLength));
      return new Vector2D(0,restLength);
   }
/**
 * obtiene vector largo del elastico.
 * @return Vector2D() largo vectorial del elastico
 */
   protected Vector2D getVector() {
   return getBendPosition().minus(getAendPosition());
   }

   /**
    * obtiene la fuerza vectorial force ejerce el elastico sobre el elemento adjunto ae.
    * @param ae objeto de la clase <b>AttachableElement</b> que experimenta la fuerza.
    * @return Vector2D force - fuerza ejecida a ae.
    */
  public Vector2D getForce(AttachableElement ae) {
  Vector2D force = new Vector2D();
  if ((a_end == null) || (b_end == null))
     return force;
  if ((ae != a_end) && (ae != b_end))
     return force;
  Vector2D RubberVector = getVector();
  double stretch = RubberVector.module() - restLength;
  if (stretch>0){
      force = RubberVector.unitary().times(stretch*stiffness);
  if (ae == a_end) return force;
  return force.times(-1.0);
  }
  else {force.set(0,0);
  return force;
  }
  }
/**
 * obtiene un string de descripcion del elastico actual.
 * @return String descripción del objeto elastico
 */
   public String getDescription() {
      return "Rubber_"+ getId()+": "+ Vector2D.getDescription()+" ,"+ Vector2D.getDescription();
   }
   /**
    * obtiene un string de descripcion de la posicion de los extremos del elastico.
    * @return String posición de los extremos
    */
   public String getState() {
      String s = getAendPosition() + "," + getBendPosition();
      return s;
   }
   
}
